package org.sardine.security;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

import org.apache.log4j.Logger;
import org.sardine.aop.advice.BeforeAdvice;
import org.sardine.util.Assert;
import org.sardine.util.RegexUtils;
import org.sardine.util.Wildcard;

public class MethodSecurityInterceptor implements BeforeAdvice{
	
	private final Logger log = Logger.getLogger(MethodSecurityInterceptor.class);
	private Map<String,String> authorizationList = new HashMap<String,String>();
	private String authorizationDescription;
	private AuthenticationManager authenticationManager;

	/**
	 * 
	 * 采用黑名单拦截机制，在名单中的方法才进行审查，不在名单中的方法直接批准调用
	 * 
	 * 由于名单中的方法授权描述（authorizationDescription）允许通配符，所以有机会出现一个尝试调用的方法名匹配多个方法授权描述.
	 * 
	 * 例如
	 * SUPER 调用 OrderService.editVipOrder
	 * 
	 * 匹配方法授权描述有2个
	 * OrderService.edit*=SUPER,ADMIN
	 * OrderService.editVip*=ADMIN
	 * 
	 * 可是第二个必须是ADMIN，结果为false，则不批准。即只要一个结果为false，就不批准
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 */
	public void before(Method method, Object[] args, Object target) throws Throwable {
		
		String callingFullMethodName = method.getDeclaringClass().getName()+"."+method.getName()+"";
		boolean approve = true;
		String denyName;
		
		if(authenticationManager == null || authenticationManager.getAuthentications().size() == 0){
			return;
		}else{
			
			List<String> callerAuthenNames = authenticationManager.getAuthentications();
			
			Iterator<String> it = authorizationList.keySet().iterator();
			while(it.hasNext()){
				String fullyQualifiedMethodName = it.next();
				if(Wildcard.match(callingFullMethodName, fullyQualifiedMethodName)){
					approve = checkAuthorization(authorizationList.get(fullyQualifiedMethodName),callerAuthenNames);
					if(!approve){
						break;
					}
				}
			}
			if(!approve){
				throw new DenyException(callerAuthenNames+" 没有访问 "+callingFullMethodName+"() 的权限");
			}
		}
		
	}
	
	private boolean checkAuthorization(String authorizationNames,List<String> callerAuthenNames){
		
		String[] authorNames = authorizationNames.split(",");
		
		for(String callerName : callerAuthenNames){
			for(String authorizationName : authorNames){
				if(callerName.equals(authorizationName)){
					return true;
				}
			}
		}
		return false;
		
	}

	public String getAuthorizationDescription() {
		return authorizationDescription;
	}

	public void setAuthorizationDescription(String authorizationDescription) {
		
		if(!RegexUtils.matchAuthorizationDescription(authorizationDescription)){
			throw new MethodSecurityInterceptorException("授权描述的格式不符合规范：\n"+authorizationDescription);
		}
		
		this.authorizationDescription = authorizationDescription;
		parseAuthorizationDescription(this.authorizationDescription);
	}
	
	private void parseAuthorizationDescription(String authorizationDescription){
		
		//log.info(authorizationDescription);
		String[] authorizations = authorizationDescription.split(RegexUtils.DESCRIPTION_SEPARATOR);
		for(String author : authorizations){
			
			int index = author.indexOf("=");
			String fullyQualifiedMethodName = author.substring(0,index);
			String authorNames = author.substring(index+1);
			authorizationList.put(fullyQualifiedMethodName, authorNames);
			log.debug("注册了一个授权描述信息：目标为 "+fullyQualifiedMethodName+",授权给："+authorNames);
		}
		
	}

	public AuthenticationManager getAuthenticationManager() {
		return authenticationManager;
	}

	public void setAuthenticationManager(AuthenticationManager authenticationManager) {
		this.authenticationManager = authenticationManager;
	}

	
	
	

}
